using System;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
using YooAsset;
namespace Panty.Test
{ 
    public class AotGameInit : MonoBehaviour
    {
        #region 面板IP配置字段
        [SerializeField]
        private EPlayMode PlayMode = EPlayMode.EditorSimulateMode;
        [SerializeField]
        private string defaultHostServer;
        [SerializeField]
        private string fallbackHostServer;
        [SerializeField]
        private string HostServerVersion;
        public string Hotfixdllnames= "hotfix.dll";
        #endregion
        private void Awake()
        {       
            YooAssets.Initialize();
        }
        #region Yooasset初始化与资源下载验证
        async Task<bool> GotoDownload(string packageName= "DefaultPackage")
        {

            // 创建资源包裹类
            var package = YooAssets.TryGetPackage(packageName);
            if (package == null)
                package = YooAssets.CreatePackage(packageName);
            YooAssets.SetDefaultPackage(package);

            InitializationOperation initializationOperation = null;

            // 编辑器下的模拟模式
            if (PlayMode == EPlayMode.EditorSimulateMode)
            {
                var simulateBuildParam = new EditorSimulateBuildParam();
                simulateBuildParam.PackageName = packageName;
                var simulateBuildResult = EditorSimulateModeHelper.SimulateBuild(simulateBuildParam);
                var createParameters = new EditorSimulateModeParameters();
                createParameters.EditorFileSystemParameters = FileSystemParameters.CreateDefaultEditorFileSystemParameters(simulateBuildResult);
                initializationOperation = package.InitializeAsync(createParameters);
            }

            // 单机运行模式
            if (PlayMode == EPlayMode.OfflinePlayMode)
            {
                var createParameters = new OfflinePlayModeParameters();
                createParameters.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(new FileOffsetDecryption());
                initializationOperation = package.InitializeAsync(createParameters);

            }

            // 联机运行模式
            if (PlayMode == EPlayMode.HostPlayMode)
            {
                string defaultHostServer = GetHostServerURL();
                string fallbackHostServer = GetHostServerURL();
                IRemoteServices remoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
                var createParameters = new HostPlayModeParameters();
                createParameters.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(new FileOffsetDecryption());
                createParameters.CacheFileSystemParameters = FileSystemParameters.CreateDefaultCacheFileSystemParameters(remoteServices);
                initializationOperation = package.InitializeAsync(createParameters);
            }
            // WebGL运行模式
            if (PlayMode == EPlayMode.WebPlayMode)
            {
                var createParameters = new WebPlayModeParameters();
#if UNITY_WEBGL && WEIXINMINIGAME && !UNITY_EDITOR
			string defaultHostServer = GetHostServerURL();
            string fallbackHostServer = GetHostServerURL();
            IRemoteServices remoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
            createParameters.WebServerFileSystemParameters = WechatFileSystemCreater.CreateWechatFileSystemParameters(remoteServices);
#else
                createParameters.WebServerFileSystemParameters = FileSystemParameters.CreateDefaultWebServerFileSystemParameters();
#endif
                initializationOperation = package.InitializeAsync(createParameters);
            }

            await initializationOperation.Task;

            // 如果初始化失败弹出提示界面
            if (initializationOperation.Status != EOperationStatus.Succeed)
            {
                Debug.LogWarning($"{initializationOperation.Error}");
            }
            else
            {
                Debug.Log("远程资源包初始化成功");
            }

            //更新获取对比远程文件版本
            var operation = package.RequestPackageVersionAsync();
            await operation.Task;
            if (operation.Status == EOperationStatus.Succeed)
            {
                //获取成功
                string packageVersion = operation.PackageVersion;
                Debug.Log($"{packageName}:PKGS Request package Version : {packageVersion}，开始进入资源更新.....");
                var operationszy = package.UpdatePackageManifestAsync(packageVersion);
                await operationszy.Task;
                if (operationszy.Status == EOperationStatus.Succeed)
                {
                    //更新成功
                    return await Download(packageName);

                }
                else
                {
                    //更新失败
                    Debug.LogError(operationszy.Error);
                    return false;
                }
            }
            else
            {
                //版本获取更新更新失败
                Debug.LogError(operation.Error);
                return false;
            }
        }

        async Task<bool> Download(string packageName = "DefaultPackage")
        {
            int downloadingMaxNum = 10;
            int failedTryAgain = 3;
            var package = YooAssets.GetPackage(packageName);
            var downloader = package.CreateResourceDownloader(downloadingMaxNum, failedTryAgain);

            //没有需要下载的资源
            if (downloader.TotalDownloadCount == 0)
            {
                //直接进入游戏
                Debug.Log("没有需要下载的资源进入游戏成功");
                return true;
            }
            //需要下载的文件总数和总大小
            int totalDownloadCount = downloader.TotalDownloadCount;
            long totalDownloadBytes = downloader.TotalDownloadBytes;
            Debug.Log($"下载资源总数:{totalDownloadCount} 大小:{totalDownloadBytes}");
            //注册回调方法
            downloader.DownloadErrorCallback = OnDownloadErrorFunction;
            downloader.DownloadUpdateCallback = OnDownloadProgressUpdateFunction;
            downloader.DownloadFinishCallback = OnDownloadOverFunction;
            downloader.DownloadFileBeginCallback = OnStartDownloadFileFunction;

            //开启下载
            downloader.BeginDownload();

            //开启加载过渡动画
            await downloader.Task;

            //检测下载结果
            if (downloader.Status == EOperationStatus.Succeed)
            {
                //下载成功
                Debug.Log("下载成功进入游戏成功");
                return true;
            }
            else
            {
                //下载失败
                Debug.LogError("下载资源失败");
                return false;
            }
        }

        #endregion

        #region yooasset下载回调函数
        private void OnDownloadOverFunction(DownloaderFinishData data)
        {
            Debug.Log("下载" + (data.Succeed ? "成功" : "失败"));
        }

        private void OnStartDownloadFileFunction(DownloadFileData data)
        {
            Debug.Log(string.Format("开始下载：文件名：{0}, 文件大小：{1}", data.FileName, data.FileSize));
        }

        private void OnDownloadProgressUpdateFunction(DownloadUpdateData data)
        {
            Debug.Log(string.Format("文件总数：{0}, 已下载文件数：{1}, 下载总大小：{2}, 已下载大小：{3}", data.TotalDownloadCount, data.CurrentDownloadCount, data.TotalDownloadBytes, data.CurrentDownloadBytes));
        }

        private void OnDownloadErrorFunction(DownloadErrorData data)
        {
            Debug.Log(string.Format("开始下载：文件名：{0}, 文件大小：{1}", data.FileName, data.ErrorInfo));
        }

        #endregion

        #region yooasset远端资源地址查询服务类
        /// <summary>
        /// 获取资源服务器地址
        /// </summary>
        private string GetHostServerURL()
        {
            //string hostServerIP = "http://10.0.2.2"; //安卓模拟器地址
            string hostServerIP = defaultHostServer;
            string appVersions = HostServerVersion;// "v1.0";

#if UNITY_EDITOR
            if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.Android)
                return $"{hostServerIP}/CDN/Android/{appVersions}";
            else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.iOS)
                return $"{hostServerIP}/CDN/IPhone/{appVersions}";
            else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.WebGL)
                return $"{hostServerIP}/CDN/WebGL/{appVersions}";
            else
                return $"{hostServerIP}/CDN/PC/{appVersions}";
#else
        if (Application.platform == RuntimePlatform.Android)
            return $"{hostServerIP}/CDN/Android/{appVersions}";
        else if (Application.platform == RuntimePlatform.IPhonePlayer)
            return $"{hostServerIP}/CDN/IPhone/{appVersions}";
        else if (Application.platform == RuntimePlatform.WebGLPlayer)
            return $"{hostServerIP}/CDN/WebGL/{appVersions}";
        else
            return $"{hostServerIP}/CDN/PC/{appVersions}";
#endif
        }

        /// <summary>
        /// 远端资源地址查询服务类
        /// </summary>
        private class RemoteServices : IRemoteServices
        {
            private readonly string _defaultHostServer;
            private readonly string _fallbackHostServer;

            public RemoteServices(string defaultHostServer, string fallbackHostServer)
            {
                _defaultHostServer = defaultHostServer;
                _fallbackHostServer = fallbackHostServer;
            }
            string IRemoteServices.GetRemoteMainURL(string fileName)
            {
                return $"{_defaultHostServer}/{fileName}";
            }
            string IRemoteServices.GetRemoteFallbackURL(string fileName)
            {
                return $"{_fallbackHostServer}/{fileName}";
            }
        }

        /// <summary>
        /// 资源文件流加载解密类
        /// </summary>
        private class FileStreamDecryption : IDecryptionServices
        {
            /// <summary>
            /// 同步方式获取解密的资源包对象
            /// 注意：加载流对象在资源包对象释放的时候会自动释放
            /// </summary>
            DecryptResult IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo)
            {
                BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
                DecryptResult decryptResult = new DecryptResult();
                decryptResult.ManagedStream = bundleStream;
                decryptResult.Result = AssetBundle.LoadFromStream(bundleStream, fileInfo.FileLoadCRC, GetManagedReadBufferSize());
                return decryptResult;
            }

            /// <summary>
            /// 异步方式获取解密的资源包对象
            /// 注意：加载流对象在资源包对象释放的时候会自动释放
            /// </summary>
            DecryptResult IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo)
            {
                BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
                DecryptResult decryptResult = new DecryptResult();
                decryptResult.ManagedStream = bundleStream;
                decryptResult.CreateRequest = AssetBundle.LoadFromStreamAsync(bundleStream, fileInfo.FileLoadCRC, GetManagedReadBufferSize());
                return decryptResult;
            }

            /// <summary>
            /// 获取解密的字节数据
            /// </summary>
            byte[] IDecryptionServices.ReadFileData(DecryptFileInfo fileInfo)
            {
                throw new System.NotImplementedException();
            }

            /// <summary>
            /// 获取解密的文本数据
            /// </summary>
            string IDecryptionServices.ReadFileText(DecryptFileInfo fileInfo)
            {
                throw new System.NotImplementedException();
            }

            private static uint GetManagedReadBufferSize()
            {
                return 1024;
            }
        }

        /// <summary>
        /// 资源文件偏移加载解密类
        /// </summary>
        private class FileOffsetDecryption : IDecryptionServices
        {
            /// <summary>
            /// 同步方式获取解密的资源包对象
            /// 注意：加载流对象在资源包对象释放的时候会自动释放
            /// </summary>
            DecryptResult IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo)
            {
                DecryptResult decryptResult = new DecryptResult();
                decryptResult.ManagedStream = null;
                decryptResult.Result = AssetBundle.LoadFromFile(fileInfo.FileLoadPath, fileInfo.FileLoadCRC, GetFileOffset());
                return decryptResult;
            }

            /// <summary>
            /// 异步方式获取解密的资源包对象
            /// 注意：加载流对象在资源包对象释放的时候会自动释放
            /// </summary>
            DecryptResult IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo)
            {
                DecryptResult decryptResult = new DecryptResult();
                decryptResult.ManagedStream = null;
                decryptResult.CreateRequest = AssetBundle.LoadFromFileAsync(fileInfo.FileLoadPath, fileInfo.FileLoadCRC, GetFileOffset());
                return decryptResult;
            }

            /// <summary>
            /// 获取解密的字节数据
            /// </summary>
            byte[] IDecryptionServices.ReadFileData(DecryptFileInfo fileInfo)
            {
                throw new System.NotImplementedException();
            }

            /// <summary>
            /// 获取解密的文本数据
            /// </summary>
            string IDecryptionServices.ReadFileText(DecryptFileInfo fileInfo)
            {
                throw new System.NotImplementedException();
            }

            private static ulong GetFileOffset()
            {
                return 32;
            }
        }
        /// <summary>
        /// 资源文件解密流
        /// </summary>
        public class BundleStream : FileStream
        {
            public const byte KEY = 64;

            public BundleStream(string path, FileMode mode, FileAccess access, FileShare share) : base(path, mode, access, share)
            {
            }
            public BundleStream(string path, FileMode mode) : base(path, mode)
            {
            }

            public override int Read(byte[] array, int offset, int count)
            {
                var index = base.Read(array, offset, count);
                for (int i = 0; i < array.Length; i++)
                {
                    array[i] ^= KEY;
                }
                return index;
            }
        }

        #endregion



        private async void Start()
        {
            //远程资源热更新下载对比
          var p1= await GotoDownload();
          var p2=  await GotoDownload("WDFS");
            if (p1 && p2) {

                StartLoadHotfixDll();
            }

        }

        private async void StartLoadHotfixDll()
        {
            var packages = YooAssets.GetPackage("DefaultPackage");
#if !UNITY_EDITOR
            //加载热更新DLL逻辑
            var goa = packages.LoadAssetAsync<TextAsset>(Hotfixdllnames);
            await goa.Task;
            var bts = goa.AssetObject as TextAsset;
            byte[] dllBytes = bts.bytes;
            System.Reflection.Assembly.Load(dllBytes);
            //加载aot泛型与热更新dll成功     
            Debug.Log("热更新dll加载成功");
#endif
            var go = packages.LoadAssetAsync<GameObject>("GameMain");
            await go.Task;
            var gbs= go.AssetObject as GameObject;
            var gb= Instantiate(gbs);

           // var gos = packages.LoadAssetAsync<GameObject>("ttt"); //原生资源
            //await gos.Task;
           // var gbss = gos.AssetObject as GameObject;
            //var abc = Instantiate(gbss);

            await Awaitable.WaitForSecondsAsync(5);
            DestroyImmediate(this.gameObject);


        }
        
    }
}

